SQSからLambda(Python3.7)起動でSlackにメッセージ送信する
おはようございます、もきゅりんです。
先日、SQSからのLambda起動でSlackメッセージ送信を実装したので、忘れないうちにまとめておきます。
やること
- LambdaからSQSにメッセージ送信する
- SQSからLambdaをイベント起動する
前提条件
- SlackのWebhook URLを取得していること
- AWS CLIインストール&設定済み
どちらも設定の記事は無数にあると思うので、説明は割愛します。
ちなみに、CLIはSQSのキューを作成するだけなので、手動で作成しても問題ありませーん。
とりあえず、投げる方から作成しちゃいましょう。
LambdaからSQSにメッセージ送信する
SQSキューの作成
CLIで作成しちゃいます。
# Que作成 aws sqs create-queue --queue-name QUENAME
"moque"というキューを作りました。
Lambdaにアタッチするロールを作成
次は、Lambdaにアタッチするロールを作成します。
大雑把にSQSFullAccessで作成します。
本来は必要最小限の権限で作成します。
適当な名前で作成します。
メッセージ送信用のLambdaの作成
一から作成で進めます。
先ほど作成したロールをアタッチするのを忘れずに。
下記のように、DirectMessgeとメンション付きメッセージとで分岐させてみます。
import os import boto3 SLACK_CHANNEL = os.environ['slackChannel'] SLACK_ID = os.environ['slackId'] HOOK_URL = os.environ['webHook'] QUE_NAME = os.environ['queName'] def lambda_handler(event, context): is_dm = event['IsDM'] if is_dm == 'true': # DM sqs = boto3.resource('sqs') queue = sqs.get_queue_by_name(QueueName=QUE_NAME) message = { 'channel': '@' + str(SLACK_ID), "username": "Moqrin", "icon_emoji": ":zap:", 'text': "これはDMです" } else: # メンションメッセージ sqs = boto3.resource('sqs') queue = sqs.get_queue_by_name(QueueName=QUE_NAME) message = { 'channel': SLACK_CHANNEL, "username": "Moqrin", "icon_emoji": ":zap:", 'text': "<@%s> これはメンションです" % (str(SLACK_ID)) } response = queue.send_message(MessageBody='SlackMessage', MessageAttributes={ 'Message': { 'StringValue': str(message), 'DataType': 'String' }, })
環境変数を忘れずに設定します。
ちゃんとする場合は、WebHookを暗号化させて対応します。
slackIdは、「プロフィール & アカウント」から取得できます。
DMかどうかのテストをイベントテンプレート「Hello World」で作成します。
テストしてみましょう。
Queの中を見に行きましょう。
ポーリングします。
メッセージが入っていますね。
では、次はイベントでトリガーされるLambdaを作成します。
SQSからLambdaをイベント起動する
SQSイベントトリガーのLambdaの作成
また一から作成で進めます。
ロールは雑ですが、先ほど作成したものを利用します。
イベントソースに最初に作成したSQSを追加します。
下記、イベント発火するLambdaとなります。
import os import json import logging import ast from urllib.request import Request, urlopen from urllib.error import URLError, HTTPError HOOK_URL = os.environ['webHook'] SLACK_CHANNEL = os.environ['slackChannel'] logger = logging.getLogger() logger.setLevel(logging.INFO) def lambda_handler(event, context): message = event['Records'][0]['messageAttributes']['Message']['stringValue'] # 文字列を辞書型に変換 slack_message = ast.literal_eval(message) req = Request(HOOK_URL, json.dumps(slack_message).encode('utf-8')) try: response = urlopen(req) response.read() logger.info("Message posted to %s", slack_message['channel']) except HTTPError as e: logger.error("Request failed: %d %s", e.code, e.reason) except URLError as e: logger.error("Server connection failed: %s", e.reason)
キューに送信されたメッセージは文字列なので、辞書型に変更してjsonにします。
環境変数をこちらも設定するのを忘れずに。
保存すると、先ほどキューにいたメッセージがSlackに投げられると思います。
今度は、DMを"false"にしてみましょう。
generalにメンション付きでメッセージが届いたらOKです。
以上です、どなたかのお役に立てば幸いです。